package org.infodavid.common.services;

import java.util.Map;

import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.login.LoginException;
import javax.xml.bind.JAXBContext;
import javax.xml.transform.Source;
import javax.xml.ws.LogicalMessage;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.infodavid.common.reflect.InstantiationHelper;

/**
 * The Class LoginModule.
 */
public abstract class LoginModule implements javax.security.auth.spi.LoginModule, LogicalMessage {
  /** The singleton. */
  private static final LoginModule SINGLETON;

  /** The Constant log. */
  private static final Log LOGGER = LogFactory.getLog(LoginModule.class);

  static {
    try {
      SINGLETON = InstantiationHelper.getInstance().newInstance(LoginModule.class);
    }
    catch (final Exception e) {
      LOGGER.fatal("Can not instantiate the " + LoginModule.class.getName(), e);

      throw new Error(e);
    }
  }

  /**
   * returns the singleton.
   * @return <code>LoginModule</code>
   */
  public static LoginModule getInstance() {
    return SINGLETON;
  }

  /**
   * Instantiates a new module.
   */
  public LoginModule() {
    super();
  }

  /**
   * Do get payload.
   * @return the source
   */
  protected abstract Source doGetPayload();

  /**
   * See super class or interface. (non-Javadoc)
   * @see javax.xml.ws.LogicalMessage#getPayload()
   */
  public final Source getPayload() {
    return getInstance().doGetPayload();
  }

  /**
   * Do set payload.
   * @param payload the payload
   */
  protected abstract void doSetPayload(Source payload);

  /**
   * See super class or interface. (non-Javadoc)
   * @see javax.xml.ws.LogicalMessage#setPayload(javax.xml.transform.Source)
   */
  public final void setPayload(final Source payload) {
    getInstance().doSetPayload(payload);
  }

  /**
   * Do get payload.
   * @param context the context
   * @return the object
   */
  protected abstract Object doGetPayload(JAXBContext context);

  /**
   * See super class or interface. (non-Javadoc)
   * @see javax.xml.ws.LogicalMessage#getPayload(javax.xml.bind.JAXBContext)
   */
  public final Object getPayload(final JAXBContext context) {
    return getInstance().doGetPayload(context);
  }

  /**
   * Do set payload.
   * @param payload the payload
   * @param context the context
   */
  protected abstract void doSetPayload(Object payload, JAXBContext context);

  /**
   * See super class or interface. (non-Javadoc)
   * @see javax.xml.ws.LogicalMessage#setPayload(java.lang.Object, javax.xml.bind.JAXBContext)
   */
  public final void setPayload(final Object payload, final JAXBContext context) {
    getInstance().doSetPayload(payload, context);
  }

  /**
   * Do initialize.
   * @param subject the subject
   * @param callbackHandler the callback handler
   * @param sharedState the shared state
   * @param options the options
   */
  protected abstract void doInitialize(Subject subject, CallbackHandler callbackHandler,
      Map<String,?> sharedState, Map<String,?> options);

  /**
   * See super class or interface. (non-Javadoc)
   * @see javax.security.auth.spi.LoginModule#initialize(javax.security.auth.Subject,
   *      javax.security.auth.callback.CallbackHandler, java.util.Map, java.util.Map)
   */
  public final void initialize(final Subject subject, final CallbackHandler callbackHandler,
      final Map<String,?> sharedState, final Map<String,?> options) {
    getInstance().doInitialize(subject, callbackHandler, sharedState, options);
  }

  /**
   * Do login.
   * @return true, if successful
   * @throws LoginException the login exception
   */
  protected abstract boolean doLogin() throws LoginException;

  /**
   * See super class or interface. (non-Javadoc)
   * @see javax.security.auth.spi.LoginModule#login()
   */
  public final boolean login() throws LoginException {
    return getInstance().doLogin();
  }

  /**
   * Do commit.
   * @return true, if successful
   * @throws LoginException the login exception
   */
  protected abstract boolean doCommit() throws LoginException;

  /**
   * See super class or interface. (non-Javadoc)
   * @see javax.security.auth.spi.LoginModule#commit()
   */
  public final boolean commit() throws LoginException {
    return getInstance().doCommit();
  }

  /**
   * Do abort.
   * @return true, if successful
   * @throws LoginException the login exception
   */
  protected abstract boolean doAbort() throws LoginException;

  /**
   * See super class or interface. (non-Javadoc)
   * @see javax.security.auth.spi.LoginModule#abort()
   */
  public final boolean abort() throws LoginException {
    return getInstance().doAbort();
  }

  /**
   * Do logout.
   * @return true, if successful
   * @throws LoginException the login exception
   */
  protected abstract boolean doLogout() throws LoginException;

  /**
   * See super class or interface. (non-Javadoc)
   * @see javax.security.auth.spi.LoginModule#logout()
   */
  public final boolean logout() throws LoginException {
    return getInstance().doLogout();
  }
}
